home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / od-amiga / ami-win.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  60KB  |  1,974 lines

  1.  /* 
  2.   * UAE - The Un*x Amiga Emulator
  3.   * 
  4.   * Amiga interface
  5.   * 
  6.   * Copyright 1996,1997 Samuel Devulder.
  7.   */
  8.  
  9. /*
  10.  * NOTE:
  11.  *      - Im quite unhappy with the color allocation scheme in case of
  12.  *        EXTRA_HALFBRITE...
  13.  */
  14.  
  15. /*
  16.  * History: (Day/Month/Year)
  17.  *    long ago - Work begins; many things done; I should have kept the history
  18.  *               log up-to-date.
  19.  *    16/10/96 - Rewrote cybergfx support. (there is still a bug if the memory
  20.  *               is not linear).
  21.  *    15/11/96 - Inhibit the drive in readdevice().
  22.  *    23/11/96 - Added call to rexx_init() and gui_handle_event().
  23.  *    14/12/96 - Added support for graffiti screens.
  24.  *    14/02/97 - Now uses SetRGB32() for cybergfx screens.
  25.  *    15/02/97 - Dump iff file when ENV:UAEIFF is defined.
  26.  *    25/02/97 - Get rid of cybergfx screen direct access.. Now uses 
  27.  *               BltBitMapRastPort(). Thanks to Mats Eirik Hansen for
  28.  *               his patch from which I'm widely inspired.
  29.  *    10/05/97 - Use OpenWindowTag() for public screen. Uses Zoom,
  30.  *               SimpleRefresh.
  31.  *    20/08/97 - Removed halfv stuff (use correct_aspect instead).
  32.  *    21/08/97 - Added HAM support (yeah!).
  33.  *    05/10/97 - Added drag&drop support.
  34.  *    13/10/97 - Fixed CyberGFX crash (a missing "return" in flush_line()).
  35.  *    31/10/97 - Added support for gray output (-T). Added missing "Cyb" 
  36.  *               prefix to BitMap=NULL in graphics_leave().
  37.  *    07/12/97 - New calc_err(). UAE screen (-H2) is now a public screen.
  38.  *    25/12/97 - Now use DELTAMOVE for mouse code. Use ENV:UAESM to use 
  39.  *               pre-selected screenmode (-H2). Happy Chrismas!
  40.  */
  41.  
  42. #define USE_CYBERGFX /* undefine this if you don't have CYBERGFX includes */
  43.  
  44. /****************************************************************************/
  45.  
  46. #include <exec/execbase.h>
  47. #include <exec/memory.h>
  48.  
  49. #include <dos/dos.h>
  50.  
  51. #include <graphics/gfxbase.h>
  52. #include <graphics/displayinfo.h>
  53.  
  54. #include <libraries/asl.h>
  55. #include <intuition/pointerclass.h>
  56.  
  57. #include <proto/intuition.h>
  58. #include <proto/graphics.h>
  59. #include <proto/exec.h>
  60. #include <proto/asl.h>
  61.  
  62. #ifdef USE_CYBERGFX
  63. #ifdef __SASC
  64. #include <cybergraphics/cybergraphics.h>
  65. #include <proto/cybergraphics.h>
  66. #else
  67. #include <inline/cybergraphics.h>
  68. #endif
  69. #ifndef BMF_SPECIALFMT
  70. #define BMF_SPECIALFMT 0x80     /* should be cybergraphics.h but isn't for  */
  71.                                 /* some strange reason */
  72. #endif
  73. #endif
  74.  
  75. /****************************************************************************/
  76.  
  77. #include "sysconfig.h"
  78. #include "sysdeps.h"
  79.  
  80. #include <ctype.h>
  81. #include <signal.h>
  82. #ifdef __GNUC__
  83. #include <ix.h>
  84. #endif
  85. #ifdef __SASC
  86. extern struct ExecBase *SysBase;
  87. #endif
  88.  
  89. /****************************************************************************/
  90.  
  91. #include "config.h"
  92. #include "options.h"
  93. #include "threaddep/penguin.h"
  94. #include "uae.h"
  95. #include "memory.h"
  96. #include "custom.h"
  97. #include "readcpu.h"
  98. #include "include/memory.h" /* (or else it's od-amiga/memory.h that is used) */
  99. #include "newcpu.h"
  100. #include "xwin.h"
  101. #include "keyboard.h"
  102. #include "keybuf.h"
  103. #include "gui.h"
  104. #include "debug.h"
  105. #include "disk.h"
  106.  
  107. #define BitMap Picasso96BitMap  /* Argh! */
  108. #include "picasso96.h"
  109. #undef BitMap 
  110.  
  111. /****************************************************************************/
  112.  
  113. #define use_dither      (!currprefs.no_xhair)
  114. #define use_gray    (currprefs.use_mitshm)
  115.  
  116. #define UAEIFF "UAEIFF"        /* env: var to trigger iff dump */
  117. #define UAESM  "UAESM"         /* env: var for screen mode */  
  118.  
  119. static int need_dither;        /* well.. guess :-) */
  120. static int use_low_bandwidth;  /* this will redraw only needed places */
  121. static int use_cyb;            /* this is for cybergfx */
  122. static int use_graffiti;
  123. static int use_approx_color;
  124. int dump_iff;
  125.  
  126. extern xcolnr xcolors[4096];
  127.  
  128.  /* Keyboard and mouse */
  129.  
  130. static int keystate[256];
  131.  
  132. extern int buttonstate[3];
  133. extern int lastmx, lastmy;
  134. extern int newmousecounters;
  135.  
  136. static int inwindow;
  137.  
  138. static char *oldpixbuf;
  139.  
  140. /****************************************************************************/
  141. /*
  142.  * prototypes & global vars
  143.  */
  144. struct IntuitionBase    *IntuitionBase;
  145. struct GfxBase          *GfxBase;
  146. struct Library          *AslBase;
  147. struct Library          *CyberGfxBase;
  148.  
  149. static UBYTE            *Line;
  150. static struct RastPort  *RP;
  151. static struct Screen    *S;
  152. static struct Window    *W;
  153. static struct RastPort  *TempRPort;
  154. static struct BitMap    *BitMap;
  155. #ifdef USE_CYBERGFX
  156. static struct BitMap    *CybBitMap;
  157. #endif
  158. static struct ColorMap  *CM;
  159. static Object           *Pointer; /* for os 39 */
  160. static UWORD            *Sprite;
  161. static int              XOffset,YOffset;
  162.  
  163. static int os39;        /* kick 39 present */
  164. static int usepub;      /* use public screen */
  165. static int usecyb;      /* use cybergraphics.library */
  166. static int is_halfbrite;
  167. static int is_ham;
  168.  
  169. static int   get_color_failed;
  170. static int   maxpen;
  171. static UBYTE pen[256];
  172.  
  173. static struct BitMap *myAllocBitMap(ULONG,ULONG,ULONG,ULONG,struct BitMap *);
  174. static void set_title(void);
  175. static void myFreeBitMap(struct BitMap *);
  176. static LONG ObtainColor(ULONG, ULONG, ULONG);
  177. static void ReleaseColors(void);
  178. static int  DoSizeWindow(struct Window *,int,int);
  179. static void disk_hotkeys(void);
  180. static void graffiti_SetRGB(int,int,int,int);
  181. static void graffiti_WritePixelLine8(int,int,short,char*);
  182. static int  SaveIFF(char *filename, struct Screen *scr);
  183. static int  init_ham(void);
  184. static void ham_conv(UWORD *src, UBYTE *buf, UWORD len);
  185. static int  RPDepth(struct RastPort *RP);
  186.  
  187. /****************************************************************************/
  188.  
  189. void main_window_led(int led, int on);
  190.  
  191. extern int  rexx_init(void);
  192. extern void rexx_exit(void);
  193. extern void initpseudodevices(void);
  194. extern void closepseudodevices(void);
  195. extern char *to_unix_path(char *s);
  196. extern char *from_unix_path(char *s);
  197. extern void split_dir_file(char *src, char **dir, char **file);
  198. extern void appw_init(struct Window *W);
  199. extern void appw_exit(void);
  200. extern void appw_events(void);
  201.  
  202. extern int ievent_alive;
  203.  
  204. /****************************************************************************/
  205.  
  206. static RETSIGTYPE sigbrkhandler(int foo)
  207. {
  208.     activate_debugger();
  209. }
  210.  
  211. void setup_brkhandler(void)
  212. {
  213. #ifdef HAVE_SIGACTION
  214.     struct sigaction sa;
  215.     sa.sa_handler = (void*)sigbrkhandler;
  216.     sa.sa_flags = 0;
  217.     sa.sa_flags = SA_RESTART;
  218.     sigemptyset(&sa.sa_mask);
  219.     sigaction(SIGINT, &sa, NULL);
  220. #else
  221.     signal(SIGINT,sigbrkhandler);
  222. #endif
  223. }
  224.  
  225. /****************************************************************************/
  226.  
  227. extern UBYTE cidx[4][8*4096];
  228.  
  229. __inline__ void flush_line(int y)
  230. {
  231.     int xs = 0, len;
  232.     int yoffset = y*gfxvidinfo.rowbytes;
  233.     char *linebuf = gfxvidinfo.bufmem + yoffset;
  234.     char *src, *dst;
  235.  
  236.     if(y<0 || y>=gfxvidinfo.height) {
  237. /*       printf("flush_line out of window: %d\n", y); */
  238.        return;
  239.     }
  240.  
  241.     len = gfxvidinfo.width;
  242.  
  243.     if(is_ham) {
  244.         ham_conv((void*)linebuf,Line,len);
  245.         WritePixelLine8(RP, 0, y, len, Line, TempRPort);
  246.         return;
  247.     }
  248.  
  249. #ifdef USE_CYBERGFX
  250.     /*
  251.      * cybergfx bitmap && no dither
  252.      */
  253.     if(use_cyb && !need_dither) {
  254.         BltBitMapRastPort(CybBitMap, 0, y, 
  255.                           RP, XOffset, YOffset+y, 
  256.                           len, 1, 0xc0);
  257.         /* sam: I'm worried because BltBitMapRastPort() is known to */
  258.         /* produce spilled registers with gcc */
  259.     return;
  260.     }
  261. #endif
  262.  
  263. #if 0
  264.     if(use_graffiti && !need_dither) {
  265.         graffiti_WritePixelLine8(0, y, gfxvidinfo.rowbytes, linebuf);
  266.     }
  267. #endif
  268.  
  269.     /*
  270.      * cybergfx && dither \_ LOW_BANDWIDTH and 1 byte per pixel in the output
  271.      * or standard screen / 
  272.      */
  273.  
  274.     switch(gfxvidinfo.pixbytes) {
  275.       case 4: 
  276.         {   /* sam: we should not arrive here on the amiga */
  277.             fprintf(stderr, "Bug in flush_line() !\n");
  278.             fprintf(stderr, "use_cyb=%d\n",use_cyb);
  279.             fprintf(stderr, "need_dither=%d\n",need_dither);
  280.             fprintf(stderr, "depth=%d\n",RPDepth(RP));
  281.             fprintf(stderr, "Please return those values to maintainer.\n");
  282.             abort();
  283.             return;
  284.         } break;
  285.       case 2:
  286.         {   short *newp = (short *)linebuf;
  287.             short *oldp = (short *)(oldpixbuf + yoffset);
  288.             while (*newp++ == *oldp++) if(!--len) return;
  289.             src   = (char *)--newp; 
  290.             dst   = (char *)--oldp; 
  291.             newp += len;
  292.             oldp += len;
  293.             while (*--newp == *--oldp);
  294.             len   = 1 + (oldp - (short *)dst);
  295.             xs    = (src - linebuf)/2;
  296.             CopyMem (src, dst, len * 2);
  297.         } break;
  298.       case 1:
  299.         {   char *newp = (char *)linebuf;
  300.             char *oldp = (char *)(oldpixbuf + yoffset);
  301.             while (*newp++ == *oldp++) if(!--len) return;
  302.             src   = (char *)--newp;
  303.             dst   = (char *)--oldp; 
  304.             newp += len;
  305.             oldp += len;
  306.             while (*--newp == *--oldp);
  307.             len   = 1 + (oldp - (char *)dst);
  308.             xs    = (src - linebuf);
  309.             CopyMem (src, dst, len);
  310.         } break;
  311.       default:
  312.         abort();
  313.         break;
  314.       }
  315.     
  316.     if (need_dither) {
  317.         DitherLine(Line, (UWORD *)dst, xs, y, (len+3)&~3, 8);
  318.     } else CopyMem(dst, Line, len); 
  319.     
  320.     if (use_cyb) { /* pixbyte == 1 */
  321. #ifdef USE_CYBERGFX
  322.         BltBitMapRastPort(CybBitMap, xs, y, 
  323.                           RP, XOffset+xs, YOffset+y, 
  324.                           len, 1, 0xc0);
  325. #endif
  326.     } else if(use_graffiti) {
  327.         graffiti_WritePixelLine8(xs, y, len, Line);
  328.     } else WritePixelLine8(RP, xs + XOffset, y + YOffset, len, Line, TempRPort);
  329. }
  330.  
  331. /****************************************************************************/
  332.  
  333. void flush_block (int ystart, int ystop)
  334. {
  335.     int y;
  336. #ifdef USE_CYBERGFX
  337.     if(use_cyb && !need_dither) {
  338.         int len = gfxvidinfo.width;
  339.         BltBitMapRastPort(CybBitMap, 
  340.             0, ystart, 
  341.             RP, XOffset, YOffset+ystart, 
  342.             len, ystop-ystart+1, 0xc0);
  343.         return;
  344.     }
  345. #endif
  346.     for(y=ystart; y<=ystop; ++y) flush_line(y);
  347. }
  348.  
  349. /****************************************************************************/
  350.  
  351. void flush_screen (int ystart, int ystop)
  352. {
  353. /* WaitBOVP() ? */
  354.     char *file;
  355.     static int cpt = 0;
  356.     char name[80];
  357.  
  358.     if(!dump_iff) return;
  359.     if(!(file = getenv(UAEIFF))) return;
  360.     if(strchr(file,'%')) sprintf(name,file,cpt++);
  361.     else sprintf(name,"%s.%05d",file,cpt++);
  362.     if(W->WScreen) SaveIFF(name,W->WScreen);
  363. }
  364.  
  365. /****************************************************************************/
  366.  
  367. static int RPDepth(struct RastPort *RP)
  368. {
  369. #ifdef USE_CYBERGFX
  370.    if(use_cyb) return GetCyberMapAttr(RP->BitMap,(LONG)CYBRMATTR_DEPTH);
  371. #endif
  372.    if(use_graffiti) return 8;
  373.    return RP->BitMap->Depth;
  374. }
  375.  
  376. /****************************************************************************/
  377.  
  378. static int get_color(int r, int g, int b, xcolnr *cnp)
  379. {
  380.     int col;
  381.  
  382.    if(use_gray) r = g = b = (77*r + 151*g + 29*b) / 256;
  383.  
  384.     r *= 0x11111111;
  385.     g *= 0x11111111;
  386.     b *= 0x11111111;
  387.     col = ObtainColor(r, g, b);
  388.  
  389.     if(col == -1) {
  390.         get_color_failed = 1;
  391.         return 0;
  392.     }
  393.  
  394.     *cnp = col;
  395.     return 1;
  396. }
  397.  
  398. /****************************************************************************/
  399. /*
  400.  * FIXME: find a better way to determine closeness of colors (closer to
  401.  * human perception).
  402.  */
  403. static __inline__ void rgb2xyz(int r, int g, int b,
  404.                                int *x, int *y, int *z)
  405. {
  406.     *x = r*1024 - (g+b)*512;
  407.     *y = 886*(g-b);
  408.     *z = (r+g+b)*341;
  409. }
  410. static __inline__ int calc_err(int r1, int g1, int b1,
  411.                                int r2, int g2, int b2)
  412. {
  413.     int x1,y1,z1,x2,y2,z2;
  414.  
  415.     rgb2xyz(r1,g1,b1,&x1,&y1,&z1);
  416.     rgb2xyz(r2,g2,b2,&x2,&y2,&z2);
  417.     x1 -= x2; y1 -= y2; z1 -= z2;
  418.     return x1*x1 + y1*y1 + z1*z1;
  419. }
  420.  
  421. /****************************************************************************/
  422.  
  423. static int get_nearest_color(int r, int g, int b)
  424. {
  425.     int i, best, err, besterr;
  426.     int colors;
  427.     int br=0,bg=0,bb=0;
  428.  
  429.    if(use_gray) r = g = b = (77*r + 151*g + 29*b) / 256;
  430.  
  431.     best    = 0;
  432.     besterr = calc_err(0,0,0, 15,15,15);
  433.     colors  = is_halfbrite?32:(1<<RPDepth(RP));
  434.   
  435.     for(i=0; i<colors; i++ ) {
  436.         long rgb = GetRGB4(CM, i);
  437.         int cr, cg, cb;
  438.         
  439.         cr = (rgb >> 8) & 15;
  440.         cg = (rgb >> 4) & 15;
  441.         cb = (rgb >> 0) & 15;
  442.           
  443.         err = calc_err(r,g,b, cr,cg,cb);
  444.         
  445.         if(err < besterr) {
  446.             best = i;
  447.             besterr = err;
  448.             br=cr; bg=cg; bb=cb;
  449.         }
  450.  
  451.         if(is_halfbrite) {
  452.             cr /= 2; cg /= 2; cb /= 2;
  453.             err = calc_err(r,g,b, cr,cg,cb);
  454.             if(err < besterr) {
  455.                 best = i + 32;
  456.                 besterr = err;
  457.                 br=cr; bg=cg; bb=cb;
  458.             }
  459.         }
  460.     }
  461.     return best;
  462. }
  463.  
  464. /****************************************************************************/
  465.  
  466. static int init_colors(void)
  467. {
  468.     gfxvidinfo.can_double = 0;
  469.     if (need_dither) {
  470.         /* first try color allocation */
  471.         int bitdepth = usepub ? 8 : RPDepth(RP);
  472.         int maxcol;
  473.  
  474.         if(!use_gray && bitdepth>=3)
  475.         do {
  476.             get_color_failed = 0;
  477.             setup_dither(bitdepth, get_color);
  478.             if(get_color_failed) ReleaseColors();
  479.         } while(get_color_failed && --bitdepth>=3);
  480.         
  481.         if(!use_gray && bitdepth>=3) {
  482.             printf("Color dithering with %d bits\n",bitdepth);
  483.             return 1;
  484.         }
  485.  
  486.         /* if that fail then try grey allocation */
  487.         maxcol = 1<<(usepub ? 8 : RPDepth(RP));
  488.  
  489.         do {
  490.             get_color_failed = 0;
  491.             setup_greydither_maxcol(maxcol, get_color);
  492.             if(get_color_failed) ReleaseColors();
  493.         } while(get_color_failed && --maxcol>=2);
  494.         
  495.         /* extra pass with approximated colors */
  496.         if(get_color_failed) do {
  497.             maxcol=2;
  498.             use_approx_color = 1;
  499.             get_color_failed = 0;
  500.             setup_greydither_maxcol(maxcol, get_color);
  501.             if(get_color_failed) ReleaseColors();
  502.         } while(get_color_failed && --maxcol>=2);
  503.  
  504.         if (maxcol >= 2) {
  505.             printf("Gray dither with %d shades.\n",maxcol);
  506.             return 1;
  507.         }
  508.         
  509.         return 0; /* everything failed :-( */
  510.     }
  511.     
  512.     /* No dither */
  513.     switch(RPDepth(RP)) {
  514.       case 6: if (is_halfbrite) {
  515.         static int tab[]={
  516.         0x000, 0x00f, 0x0f0, 0x0ff, 0x08f, 0x0f8, 0xf00, 0xf0f,
  517.         0x80f, 0xff0, 0xfff, 0x88f, 0x8f0, 0x8f8, 0x8ff, 0xf08,
  518.         0xf80, 0xf88, 0xf8f, 0xff8, /* end of regular pattern */
  519.         0xa00, 0x0a0, 0xaa0, 0x00a, 0xa0a, 0x0aa, 0xaaa,
  520.         0xfaa, 0xf6a, 0xa80, 0x06a, 0x6af };
  521.         int i;
  522.         for(i=0;i<32;++i) get_color(tab[i]>>8, (tab[i]>>4)&15, tab[i]&15, xcolors);
  523.         for(i=0;i<4096;++i) xcolors[i] = get_nearest_color(i>>8, (i>>4)&15, i&15);
  524.         printf("Using %d colors + halfbrite\n",32);
  525.         break;
  526.       } else if(is_ham) {
  527.         int i;
  528.         for(i=0;i<16;++i) get_color(i,i,i, xcolors);
  529.         printf("Using %d bits pseudo-truecolor (HAM).\n",12);
  530.         alloc_colors64k(4,4,4,10,5,0);
  531.         return init_ham();
  532.       }
  533.  
  534.       case 1: case 2: case 3: case 4: case 5: case 7: case 8: {
  535.         int maxcol = 1<<RPDepth(RP);
  536.  
  537.         if(maxcol>=8 && !use_gray) do {
  538.             get_color_failed = 0;
  539.             setup_maxcol(maxcol);
  540.             alloc_colors256(get_color);
  541.             if(get_color_failed) ReleaseColors();
  542.         } while(get_color_failed && --maxcol>=8);
  543.         else {
  544.             int i;
  545.             for(i=0;i<maxcol;++i) {
  546.                 get_color((i*15)/(maxcol-1), (i*15)/(maxcol-1), 
  547.                           (i*15)/(maxcol-1), xcolors);
  548.             }
  549.         }
  550.         printf("Using %d colors.\n",maxcol);
  551.         for(maxcol=0; maxcol<4096; ++maxcol)
  552.             xcolors[maxcol] = get_nearest_color(maxcol>>8, (maxcol>>4)&15, 
  553.                                                 maxcol&15);
  554.         } break;
  555.  
  556.       case 15:
  557.         printf("Using %d bits truecolor.\n",15);
  558.         alloc_colors64k(5,5,5,10,5,0);
  559.         break;
  560.  
  561.       case 16:
  562.         printf("Using %d bits truecolor.\n",16);
  563.         alloc_colors64k(5,6,5,11,5,0);
  564.         break;
  565.  
  566.       case 24: 
  567.         printf("Using %d bits truecolor.\n",24);
  568.         alloc_colors64k(8,8,8,16,8,0);
  569.         break;
  570.  
  571.       case 32: 
  572.         printf("Using %d bits truecolor.\n",32);
  573.         alloc_colors64k(8,8,8,16,8,0);
  574.         break;
  575.     }
  576.     return 1;
  577. }
  578.  
  579. /****************************************************************************/
  580.  
  581. static void setup_sprite(struct Window *W)
  582. {
  583.     Sprite = AllocVec(4+2, MEMF_CHIP|MEMF_CLEAR);
  584.     if(!Sprite) {
  585.        fprintf(stderr, "Warning: Can't alloc sprite buffer !\n");
  586.        return;
  587.     }
  588.     Sprite[2] = 0x8000; Sprite[3] = 0x8000;
  589.     SetPointer(W, Sprite, 1, 16, -1, 0);
  590. }
  591.  
  592. /****************************************************************************/
  593.  
  594. static int setup_customscreen(void)
  595. {
  596.     /* hum some of old programming style here :) */
  597.     static struct NewScreen NewScreenStructure = {
  598.         0,0, 800,600, 3, 0,1,
  599.         LACE+HIRES, CUSTOMSCREEN|SCREENQUIET|SCREENBEHIND,
  600.         NULL, (void*)"UAE", NULL, NULL};
  601.     static struct NewWindow NewWindowStructure = {
  602.         0,0, 800,600, 0,1,
  603.         IDCMP_MOUSEBUTTONS|IDCMP_RAWKEY|IDCMP_DISKINSERTED|IDCMP_DISKREMOVED|
  604.         IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW|IDCMP_MOUSEMOVE|
  605.         IDCMP_DELTAMOVE,
  606.         WFLG_SMART_REFRESH|WFLG_BACKDROP|WFLG_RMBTRAP|WFLG_NOCAREREFRESH|
  607.         WFLG_BORDERLESS|WFLG_WINDOWACTIVE|WFLG_REPORTMOUSE,
  608.         NULL, NULL, (void*)"UAE", NULL, NULL, 5,5, 800,600,
  609.         CUSTOMSCREEN};
  610.  
  611.     NewScreenStructure.Width     = currprefs.gfx_width;
  612.     NewScreenStructure.Height    = currprefs.gfx_height;
  613.     NewScreenStructure.Depth     = os39?8:(currprefs.gfx_lores?5:4);
  614.     NewScreenStructure.ViewModes = SPRITES | (currprefs.gfx_lores?NULL:HIRES) |
  615.                                    (currprefs.gfx_height>256?LACE:NULL);
  616.   
  617.     do S = (void*)OpenScreen(&NewScreenStructure);
  618.     while(!S && --NewScreenStructure.Depth);
  619.     if(!S) {
  620.         fprintf(stderr, "Can't open custom screen !\n");
  621.         return 0;
  622.     }
  623.  
  624.     CM = S->ViewPort.ColorMap;
  625.     RP = &S->RastPort;
  626.  
  627.     NewWindowStructure.Width  = S->Width;
  628.     NewWindowStructure.Height = S->Height;
  629.     NewWindowStructure.Screen = S;
  630.     W = (void*)OpenWindow(&NewWindowStructure);
  631.     if(!W) {
  632.         fprintf(stderr, "Can't open window on custom screen !\n");
  633.         return 0;
  634.     }
  635.     setup_sprite(W);
  636.     return 1;
  637. }
  638.  
  639. /****************************************************************************/
  640.  
  641. static int setup_publicscreen(void)
  642. {
  643.     UWORD ZoomArray[4] = {0,0,0,0};
  644.   
  645.     S = LockPubScreen(NULL);
  646.     if(!S) {
  647.         fprintf(stderr,"No public screen !\n");
  648.         return 0;
  649.     }
  650.  
  651.     ZoomArray[2] = 128;
  652.     ZoomArray[3] = S->BarHeight+1;
  653.  
  654.     CM = S->ViewPort.ColorMap;
  655.  
  656.     if((S->ViewPort.Modes & (HIRES|LACE))==HIRES) {
  657.         if(currprefs.gfx_height + S->BarHeight + 1 >= S->Height) {
  658.             currprefs.gfx_height >>= 1;
  659.             currprefs.gfx_correct_aspect = 1;
  660.         }
  661.     }
  662.  
  663. #ifdef USE_CYBERGFX
  664.     if(CyberGfxBase && IsCyberModeID(GetVPModeID(&S->ViewPort))) use_cyb = 1;
  665. #endif
  666.     W = OpenWindowTags(NULL,
  667.                        WA_Title,        (ULONG)"UAE",
  668.                        WA_AutoAdjust,   TRUE,
  669.                        WA_InnerWidth,   currprefs.gfx_width,
  670.                        WA_InnerHeight,  currprefs.gfx_height,
  671.                        WA_PubScreen,    (ULONG)S,
  672.                        WA_Zoom,         (ULONG)ZoomArray,
  673.                        WA_IDCMP,        IDCMP_MOUSEBUTTONS|
  674.                                         IDCMP_RAWKEY|
  675.                                         IDCMP_ACTIVEWINDOW|
  676.                                         IDCMP_INACTIVEWINDOW|
  677.                                         IDCMP_MOUSEMOVE|
  678.                                         IDCMP_DELTAMOVE|
  679.                                         IDCMP_CLOSEWINDOW|
  680.                                         IDCMP_REFRESHWINDOW|
  681.                                         IDCMP_NEWSIZE|
  682.                                         0,
  683.                        WA_Flags,        WFLG_DRAGBAR|
  684.                                         WFLG_DEPTHGADGET|
  685.                                         WFLG_REPORTMOUSE|
  686.                                         WFLG_RMBTRAP|
  687.                                         WFLG_ACTIVATE|
  688.                                         WFLG_CLOSEGADGET|
  689.                                         WFLG_SMART_REFRESH|
  690.                                         0,
  691.                        TAG_DONE);
  692.       
  693.     UnlockPubScreen(NULL, S);
  694.  
  695.     if(!W) {
  696.         fprintf(stderr,"Can't open window on public screen !\n");
  697.         CM = NULL;
  698.         return 0;
  699.     }
  700.  
  701.     gfxvidinfo.width  = (W->Width  - W->BorderRight - W->BorderLeft);
  702.     gfxvidinfo.height = (W->Height - W->BorderTop   - W->BorderBottom);
  703.     XOffset = W->BorderLeft;
  704.     YOffset = W->BorderTop;
  705.  
  706.     RP = W->RPort;
  707.     setup_sprite(W);
  708.  
  709.     appw_init(W);
  710.  
  711.     return 1;
  712. }
  713.  
  714. /****************************************************************************/
  715.  
  716. static char *get_num(char *s, int *n)
  717. {
  718.    int i=0;
  719.    while(isspace(*s)) ++s;
  720.    if(*s=='0') {
  721.      ++s;
  722.      if(*s=='x' || *s=='X') {
  723.        do {char c=*++s; 
  724.            if(c>='0' && c<='9') {i*=16; i+= c-'0';}    else
  725.            if(c>='a' && c<='f') {i*=16; i+= c-'a'+10;} else
  726.            if(c>='A' && c<='F') {i*=16; i+= c-'A'+10;} else break;
  727.        } while(1);
  728.      } else while(*s>='0' && *s<='7') {i*=8; i+= *s++ - '0';}
  729.    } else {
  730.      while(*s>='0' && *s<='9') {i*=10; i+= *s++ - '0';}
  731.    }
  732.    *n=i;
  733.    while(isspace(*s)) ++s;
  734.    return s;
  735. }
  736.  
  737. /****************************************************************************/
  738.  
  739. static void get_displayid(ULONG *DI, LONG *DE)
  740. {
  741.    char *s;
  742.    int di,de;
  743.  
  744.    *DI=INVALID_ID;
  745.    s=getenv(UAESM);if(!s) return;
  746.    s=get_num(s,&di);
  747.    if(*s!=':') return;
  748.    s=get_num(s+1,&de);
  749.    if(!de) return;
  750.    *DI=di; *DE=de;
  751. }
  752.  
  753. /****************************************************************************/
  754.  
  755. static int setup_userscreen(void)
  756. {
  757.     struct ScreenModeRequester *ScreenRequest;
  758.     ULONG DisplayID;
  759.     static struct BitMap PointerBitMap;
  760.     UWORD *PointerLine;
  761.     LONG ScreenWidth=0,ScreenHeight=0,Depth=0;
  762.     UWORD OverscanType=OSCAN_STANDARD;
  763.     BOOL AutoScroll=TRUE;
  764.  
  765.     if(!AslBase) AslBase = OpenLibrary("asl.library",38);
  766.     if(!AslBase) {
  767.         fprintf(stderr,"Can't open asl.library v38 !");
  768.         return 0;
  769.     }
  770.  
  771.     ScreenRequest = AllocAslRequest(ASL_ScreenModeRequest,NULL);
  772.     if(!ScreenRequest) {
  773.         fprintf(stderr,"Unable to allocate screen mode requester.\n");
  774.         return 0;
  775.     }
  776.  
  777.     get_displayid(&DisplayID, &Depth);
  778.  
  779.     if(DisplayID==(ULONG)INVALID_ID) {
  780.     if(AslRequestTags(ScreenRequest,
  781.                       ASLSM_TitleText, (ULONG)"Select screen display mode",
  782.                       ASLSM_InitialDisplayID,    NULL,
  783.                       ASLSM_InitialDisplayDepth, 8,
  784.                       ASLSM_InitialDisplayWidth, currprefs.gfx_width,
  785.                       ASLSM_InitialDisplayHeight,currprefs.gfx_height,
  786.                       ASLSM_MinWidth,            currprefs.gfx_width,
  787.                       ASLSM_MinHeight,           currprefs.gfx_height,
  788.                       ASLSM_DoWidth,             TRUE,
  789.                       ASLSM_DoHeight,            TRUE,
  790.                       ASLSM_DoDepth,             TRUE,
  791.                       ASLSM_DoOverscanType,      TRUE,
  792.                       ASLSM_PropertyFlags,       0,
  793.                       ASLSM_PropertyMask,        DIPF_IS_DUALPF | 
  794.                                                  DIPF_IS_PF2PRI | 
  795.                                                  0,
  796.                       TAG_DONE)) {
  797.         ScreenWidth  = ScreenRequest->sm_DisplayWidth;
  798.         ScreenHeight = ScreenRequest->sm_DisplayHeight;
  799.         Depth        = ScreenRequest->sm_DisplayDepth;
  800.         DisplayID    = ScreenRequest->sm_DisplayID;
  801.         OverscanType = ScreenRequest->sm_OverscanType;
  802.         AutoScroll   = ScreenRequest->sm_AutoScroll;
  803.         }
  804.     else DisplayID = INVALID_ID;
  805.     }
  806.     FreeAslRequest(ScreenRequest);
  807.     
  808.     if(DisplayID == (ULONG)INVALID_ID) return 0;
  809.  
  810. #ifdef USE_CYBERGFX 
  811.     if(CyberGfxBase && IsCyberModeID(DisplayID)) use_cyb = 1;
  812. #endif
  813.     if(DisplayID & DIPF_IS_HAM) Depth = 6; /* only ham6 for the moment */
  814.     if(ScreenWidth  < currprefs.gfx_width)  ScreenWidth  = currprefs.gfx_width;
  815.     if(ScreenHeight < currprefs.gfx_height) ScreenHeight = currprefs.gfx_height;
  816.  
  817.     S = OpenScreenTags(NULL,
  818.                        SA_DisplayID,                  DisplayID,
  819.                        SA_Width,                      ScreenWidth,
  820.                        SA_Height,                     ScreenHeight,
  821.                        SA_Depth,                      Depth,
  822.                        SA_Overscan,                   OverscanType,
  823.                        SA_AutoScroll,                 AutoScroll,
  824.                        SA_ShowTitle,                  FALSE,
  825.                        SA_Quiet,                      TRUE,
  826.                        SA_Behind,                     TRUE,
  827.                        SA_PubName,               (ULONG)"UAE",
  828.                        /* v39 stuff here: */
  829.                        (os39?SA_BackFill:TAG_DONE),   (ULONG)LAYERS_NOBACKFILL,
  830.                        SA_SharePens,                  TRUE,
  831.                        SA_Exclusive,                  (use_cyb?TRUE:FALSE),
  832.                        SA_Draggable,                  (use_cyb?FALSE:TRUE),
  833.                        SA_Interleaved,                TRUE,
  834.                        TAG_DONE);
  835.     if(!S) {
  836.         fprintf(stderr,"Unable to open the screen.\n");
  837.         return 0;
  838.     }
  839.     
  840.     CM           = S->ViewPort.ColorMap;
  841.     is_halfbrite = (S->ViewPort.Modes & EXTRA_HALFBRITE);
  842.     is_ham       = (S->ViewPort.Modes & HAM);
  843.  
  844.     PointerLine  = malloc(4);/* autodocs says it needs not be in chip memory */
  845.     if(PointerLine) PointerLine[0]=PointerLine[1]=0;
  846.     InitBitMap(&PointerBitMap,2,16,1);
  847.     PointerBitMap.Planes[0] = (PLANEPTR)&PointerLine[0];
  848.     PointerBitMap.Planes[1] = (PLANEPTR)&PointerLine[1];
  849.  
  850.     Pointer = NewObject(NULL,POINTERCLASS,
  851.                         POINTERA_BitMap,        (ULONG)&PointerBitMap,
  852.                         POINTERA_WordWidth,     1,
  853.                         TAG_DONE);
  854.     if(!Pointer)
  855.         fprintf(stderr,"Warning: Unable to allocate blank mouse pointer.\n");
  856.  
  857.     W = OpenWindowTags(NULL,
  858.                        WA_Width,                S->Width,
  859.                        WA_Height,               S->Height,
  860.                        WA_CustomScreen,         (ULONG)S,
  861.                        WA_Backdrop,             TRUE,
  862.                        WA_Borderless,           TRUE,
  863.                        WA_RMBTrap,              TRUE,
  864.                        WA_ReportMouse,          TRUE,
  865.                        WA_IDCMP,                IDCMP_MOUSEBUTTONS|
  866.                                                 IDCMP_RAWKEY|
  867.                                                 IDCMP_DISKINSERTED|
  868.                                                 IDCMP_DISKREMOVED|
  869.                                                 IDCMP_ACTIVEWINDOW|
  870.                                                 IDCMP_INACTIVEWINDOW|
  871.                                                 IDCMP_MOUSEMOVE|
  872.                                                 IDCMP_DELTAMOVE,
  873.                        (os39?WA_BackFill:TAG_IGNORE), (ULONG)LAYERS_NOBACKFILL,
  874.                        (Pointer?WA_Pointer:TAG_IGNORE), (ULONG)Pointer,
  875.                        TAG_DONE);
  876.  
  877.     if(!W) {
  878.         fprintf(stderr,"Unable to open the window.\n");
  879.         CloseScreen(S);S=NULL;RP=NULL;CM=NULL;
  880.         return 0;
  881.     }
  882.     if(!Pointer) setup_sprite(W);
  883.  
  884.     RP = W->RPort; /* &S->Rastport if screen is not public */
  885.     PubScreenStatus(S, 0);
  886.     printf("Using screenmode: 0x%08x:%d (%u:%d)\n",
  887.            DisplayID,Depth, DisplayID,Depth);
  888.    
  889.     return 1;
  890. }
  891.  
  892. /****************************************************************************/
  893.  
  894. static int setup_graffiti(void)
  895. {
  896.     static struct NewScreen NewScreenStructure = {
  897.         0,0, 800,600, 4, 0,1,
  898.         HIRES, CUSTOMSCREEN|SCREENQUIET/*|SCREENBEHIND*/,
  899.         NULL, (void*)"UAE", NULL, NULL};
  900.     static struct NewWindow NewWindowStructure = {
  901.         0,0, 800,600, 0,1,
  902.         IDCMP_MOUSEBUTTONS|IDCMP_RAWKEY|IDCMP_DISKINSERTED|IDCMP_DISKREMOVED|
  903.         IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW|IDCMP_MOUSEMOVE|
  904.     IDCMP_DELTAMOVE,
  905.         WFLG_SMART_REFRESH|WFLG_BACKDROP|WFLG_RMBTRAP|WFLG_NOCAREREFRESH|
  906.         WFLG_BORDERLESS|WFLG_WINDOWACTIVE|WFLG_REPORTMOUSE,
  907.         NULL, NULL, (void*)"UAE", NULL, NULL, 5,5, 800,600,
  908.         CUSTOMSCREEN};
  909.     static short colarr[] = {
  910.         0x000,0x001,0x008,0x009,0x080,0x081,0x088,0x089,
  911.         0x800,0x801,0x808,0x809,0x880,0x881,0x888,0x889};
  912.     int i;
  913.  
  914.     NewScreenStructure.Width     = 2*currprefs.gfx_width;
  915.     /* I leave 8 extra lines for palette & mode: */
  916.     NewScreenStructure.Height    = currprefs.gfx_height+8;  
  917.     NewScreenStructure.Depth     = 4;
  918.     NewScreenStructure.ViewModes = HIRES|GENLOCK_AUDIO/*|GENLOCK_VIDEO*/;
  919.                                    /*    ^^            ^^ which one ? */
  920.   
  921.     S = (void*)OpenScreen(&NewScreenStructure);
  922.     if(!S) {
  923.         fprintf(stderr, "Can't open graffiti screen !\n");
  924.         return 0;
  925.     }
  926.  
  927.     for(i=0;i<15;++i) {
  928.         unsigned int rgb = colarr[i];
  929.         SetRGB4(&S->ViewPort,i,(rgb>>8)&15,(rgb>>4)&15,rgb&15);
  930.     }
  931.  
  932.     CM = S->ViewPort.ColorMap;
  933.     RP = &S->RastPort;
  934.  
  935.     NewWindowStructure.Width  = S->Width;
  936.     NewWindowStructure.Height = S->Height;
  937.     NewWindowStructure.Screen = S;
  938.     W = (void*)OpenWindow(&NewWindowStructure);
  939.     if(!W) {
  940.         fprintf(stderr, "Can't open window on graffiti screen !\n");
  941.         return 0;
  942.     }
  943.     setup_sprite(W);
  944.     {
  945.     /* make sure cmd part is cleared */
  946.     int d;
  947.     for(d = 0; d < 4; ++d) {
  948.         short *p;
  949.         int i;
  950.         p = (void*)RP->BitMap->Planes[d];
  951.         for(i=0;i<40*7;++i) p[i] = 0;
  952.     }
  953.     /* set graffiti mode to lores */
  954.     *((short*)RP->BitMap->Planes[3]+8*40-1) = 0x0800;
  955.     for(d=0;d<256;++d) graffiti_SetRGB(d,0,0,0);
  956.     }
  957.  
  958.     return 1;
  959. }
  960.  
  961. /****************************************************************************/
  962.  
  963. int graphics_setup(void)
  964. {
  965. #ifdef OS_IS_AMIGAOS
  966.     if(ix_os != OS_IS_AMIGAOS) {
  967.         ix_req(NULL, "Abort", NULL, "That version of %s is only for AmigaOS!", __progname);
  968.         exit(20);
  969.     }    
  970. #endif
  971.     if(SysBase->LibNode.lib_Version < 36) {
  972.         fprintf(stderr, "UAE needs OS 2.0+ !\n");
  973.         return 0;
  974.     }
  975.     os39   = (SysBase->LibNode.lib_Version>=39);
  976.  
  977.     atexit(graphics_leave);
  978.  
  979.     IntuitionBase = (void*)OpenLibrary("intuition.library",0L);
  980.     if(!IntuitionBase) {
  981.         fprintf(stderr,"No intuition.library ?\n");
  982.         return 0;
  983.     }
  984.     GfxBase = (void*)OpenLibrary("graphics.library",0L);
  985.     if(!GfxBase) {
  986.         fprintf(stderr,"No graphics.library ?\n");
  987.         return 0;
  988.     }
  989. #ifdef USE_CYBERGFX
  990.     if(!CyberGfxBase) CyberGfxBase = OpenLibrary("cybergraphics.library",40);
  991. #endif
  992.     initpseudodevices();
  993.  
  994.     return 1;
  995. }
  996.  
  997. /****************************************************************************/
  998.  
  999. int graphics_init(void)
  1000. {
  1001.     int i,bitdepth;
  1002.  
  1003.     use_low_bandwidth = 0;
  1004.     need_dither = 0;
  1005.     use_cyb = 0;
  1006.     
  1007.     if (currprefs.gfx_width < 320)
  1008.         currprefs.gfx_width = 320;
  1009.     if (!currprefs.gfx_correct_aspect && (currprefs.gfx_height < 64/*200*/))
  1010.         currprefs.gfx_height = 200;
  1011.     currprefs.gfx_width += 7;
  1012.     currprefs.gfx_width &= ~7;
  1013.  
  1014.     if (currprefs.color_mode > 5)
  1015.         fprintf(stderr, "Bad color mode selected. Using default.\n"), currprefs.color_mode = 0;
  1016.     
  1017.     if(currprefs.color_mode == 3) { /* graffiti */
  1018.         currprefs.gfx_width = 320;
  1019.         if(currprefs.gfx_height > 256) 
  1020.             currprefs.gfx_height = 256;
  1021.         currprefs.gfx_lores = 1;
  1022.     } /* graffiti */
  1023.     
  1024.     gfxvidinfo.width  = currprefs.gfx_width;
  1025.     gfxvidinfo.height = currprefs.gfx_height;
  1026.  
  1027.     switch(currprefs.color_mode) {
  1028.       case 3:
  1029.         if(setup_graffiti()) {use_graffiti = 1;break;}
  1030.         fprintf(stderr,"Asking user for screen...\n");
  1031.         /* fall trough */
  1032.       case 2:
  1033.         if(setup_userscreen()) break;
  1034.         fprintf(stderr,"Trying on public screen...\n");
  1035.         /* fall trough */
  1036.       case 1:
  1037.         is_halfbrite = 0;
  1038.         if(setup_publicscreen()) {usepub = 1;break;}
  1039.         fprintf(stderr,"Trying on custom screen...\n");
  1040.         /* fall trough */
  1041.       case 0:
  1042.       default:
  1043.         if(!setup_customscreen()) return 0;
  1044.         break;
  1045.     }
  1046.  
  1047.     Line = AllocVec((currprefs.gfx_width + 15) & ~15,MEMF_ANY|MEMF_PUBLIC);
  1048.     if(!Line) {
  1049.         fprintf(stderr,"Unable to allocate raster buffer.\n");
  1050.         return 0;
  1051.     }
  1052.     BitMap = myAllocBitMap(currprefs.gfx_width,1,8,BMF_CLEAR|BMF_MINPLANES,RP->BitMap);
  1053.     if(!BitMap) {
  1054.         fprintf(stderr,"Unable to allocate BitMap.\n");
  1055.         return 0;
  1056.     }
  1057.     TempRPort = AllocVec(sizeof(struct RastPort),MEMF_ANY|MEMF_PUBLIC);
  1058.     if(!TempRPort) {
  1059.         fprintf(stderr,"Unable to allocate RastPort.\n");
  1060.         return 0;
  1061.     }
  1062.     CopyMem(RP,TempRPort,sizeof(struct RastPort));
  1063.     TempRPort->Layer  = NULL;
  1064.     TempRPort->BitMap = BitMap;
  1065.  
  1066.     if(usepub) set_title();
  1067.  
  1068.     bitdepth = RPDepth(RP);
  1069.     if(is_ham) {
  1070.         /* ham 6 */
  1071.         use_low_bandwidth   = 0; /* needless as the line must be fully */
  1072.         need_dither         = 0; /* recomputed */
  1073.         gfxvidinfo.pixbytes = 2;
  1074.     } else if(bitdepth <= 8) {
  1075.         /* chunk2planar is slow so we define use_low_bandwidth for all modes
  1076.            except cybergraphics modes */
  1077.         use_low_bandwidth   = 1; 
  1078.         need_dither         = use_dither || (bitdepth<=1);
  1079.         gfxvidinfo.pixbytes = need_dither?2:1;
  1080.     } else {
  1081.         /* Cybergfx mode */
  1082.         gfxvidinfo.pixbytes = (bitdepth == 24 || bitdepth == 32) ? 4 :
  1083.                               (bitdepth == 12 || bitdepth == 16) ? 2 : 1;
  1084.     }
  1085.     
  1086.     if (!use_cyb) {
  1087.         gfxvidinfo.rowbytes = gfxvidinfo.pixbytes * currprefs.gfx_width;
  1088.         gfxvidinfo.bufmem = (char *)calloc(gfxvidinfo.rowbytes, currprefs.gfx_height+1);
  1089.         /*                                                           ^^ */
  1090.         /*            This is because DitherLine may read one extra row */
  1091.     } else {
  1092. #ifdef USE_CYBERGFX
  1093.         ULONG fmt = 0;
  1094.         switch(bitdepth) {
  1095.            case 8:  fmt = PIXFMT_LUT8; break;
  1096.            case 15: fmt = PIXFMT_RGB15; break;
  1097.            case 16: fmt = PIXFMT_RGB16; break;
  1098.            case 24: fmt = PIXFMT_RGB24; break;
  1099.            case 32: fmt = PIXFMT_ARGB32; break;
  1100.            default: fprintf(stderr,"Unsupported bitdepth %d.\n",bitdepth); return 0;
  1101.         }
  1102.         CybBitMap = myAllocBitMap(currprefs.gfx_width, currprefs.gfx_height+1,
  1103.                                   bitdepth, 
  1104.                                   (fmt<<24)|BMF_SPECIALFMT|BMF_MINPLANES, 
  1105.                                   NULL);
  1106.         if(CybBitMap) {
  1107.            gfxvidinfo.rowbytes = GetCyberMapAttr(CybBitMap,CYBRMATTR_XMOD);
  1108.            gfxvidinfo.pixbytes = GetCyberMapAttr(CybBitMap,CYBRMATTR_BPPIX);
  1109.            gfxvidinfo.bufmem = (char *)GetCyberMapAttr(CybBitMap,CYBRMATTR_DISPADR);
  1110.         } else gfxvidinfo.bufmem = NULL;
  1111. #endif
  1112.     } 
  1113.     if(!gfxvidinfo.bufmem) {
  1114.         fprintf(stderr,"Not enough memory for video bufmem.\n");
  1115.         return 0;
  1116.     } 
  1117.  
  1118.     if (use_low_bandwidth) {
  1119.         gfxvidinfo.maxblocklines = currprefs.gfx_height-1; /* it seems to increase the speed */
  1120.         oldpixbuf = (char *)calloc(gfxvidinfo.rowbytes, currprefs.gfx_height);
  1121.         if(!oldpixbuf) {
  1122.             fprintf(stderr,"Not enough memory for oldpixbuf.\n");
  1123.             return 0;
  1124.         }
  1125.     } else {
  1126.         gfxvidinfo.maxblocklines = 0; /* whatever... */
  1127.     }
  1128.  
  1129.     if (!init_colors()) {
  1130.         fprintf(stderr,"Failed to init colors.\n");
  1131.         return 0;
  1132.     }
  1133.     switch (gfxvidinfo.pixbytes) {
  1134.      case 2:
  1135.         for (i = 0; i < 4096; i++) xcolors[i] *= 0x00010001;
  1136.         gfxvidinfo.can_double = 1;
  1137.         break;
  1138.      case 1:
  1139.         for (i = 0; i < 4096; i++) xcolors[i] *= 0x01010101;
  1140.         gfxvidinfo.can_double = 1;
  1141.         break;
  1142.      default:
  1143.         gfxvidinfo.can_double = 0;
  1144.         break;
  1145.     }
  1146.  
  1147.     if(!usepub) ScreenToFront(S);
  1148.  
  1149.     buttonstate[0] = buttonstate[1] = buttonstate[2] = 0;
  1150.     for(i=0; i<256; i++)
  1151.         keystate[i] = 0;
  1152.     
  1153.     lastmx = lastmy = 0; 
  1154.     newmousecounters = 0;
  1155.     inwindow = 0;
  1156.  
  1157.     rexx_init();
  1158.  
  1159.     if(getenv(UAEIFF) && !use_cyb) {
  1160.         dump_iff = 1;
  1161.         fprintf(stderr,"Saving to \"%s\"\n",getenv(UAEIFF));
  1162.     }
  1163.  
  1164.     return 1;
  1165. }
  1166.  
  1167. /****************************************************************************/
  1168.  
  1169. void graphics_leave(void)
  1170. {
  1171.     rexx_exit();
  1172.     closepseudodevices();
  1173.     appw_exit();
  1174. #ifdef USE_CYBERGFX
  1175.     if(CybBitMap) {
  1176.         WaitBlit();
  1177.         myFreeBitMap(CybBitMap);
  1178.         CybBitMap = NULL;
  1179.     }
  1180. #endif
  1181.     if(BitMap) {
  1182.         WaitBlit();
  1183.         myFreeBitMap(BitMap);
  1184.         BitMap = NULL;
  1185.     }
  1186.     if(TempRPort) {
  1187.         FreeVec(TempRPort);
  1188.         TempRPort = NULL;
  1189.     }
  1190.     if(Line) {
  1191.         FreeVec(Line);
  1192.         Line = NULL;
  1193.     } 
  1194.     if(CM) {
  1195.         ReleaseColors();
  1196.         CM = NULL;
  1197.     }
  1198.     if(W) {
  1199.         CloseWindow(W);
  1200.         W = NULL;
  1201.     }
  1202.     if(Sprite) {
  1203.         FreeVec(Sprite);
  1204.         Sprite = NULL;
  1205.     }
  1206.     if(Pointer) {
  1207.         DisposeObject(Pointer);
  1208.         Pointer = NULL;
  1209.     }
  1210.     if(!usepub && S) {
  1211.     int warn = 0;
  1212.         if(!CloseScreen(S)) {
  1213.            fprintf(stderr,"Please close all opened windows on UAE's "
  1214.                   "screen.\n");
  1215. #ifdef __SASC
  1216.        do Delay(50); while(!CloseScreen(S));
  1217. #else
  1218.        do sleep(1); while(!CloseScreen(S));
  1219. #endif
  1220.     }
  1221.         S = NULL;
  1222.     }
  1223.     if(AslBase) {
  1224.         CloseLibrary((void*)AslBase);
  1225.         AslBase = NULL;
  1226.     }
  1227.     if(GfxBase) {
  1228.         CloseLibrary((void*)GfxBase);
  1229.         GfxBase = NULL;
  1230.     }
  1231.     if(IntuitionBase) {
  1232.         CloseLibrary((void*)IntuitionBase);
  1233.         IntuitionBase = NULL;
  1234.     }
  1235.     if(CyberGfxBase) {
  1236.         CloseLibrary((void*)CyberGfxBase);
  1237.         CyberGfxBase = NULL;
  1238.     }
  1239. }
  1240.  
  1241.  
  1242. /***************************************************************************/
  1243.  
  1244. void handle_events(void)
  1245. {
  1246.     struct IntuiMessage *msg;
  1247.     int dmx,dmy,class,code;
  1248.   
  1249.     newmousecounters = 0;
  1250.     
  1251.     /*
  1252.      * This is a hack to simulate ^C as is seems that break_handler
  1253.      * is lost when system() is called.
  1254.      */
  1255.     if(SetSignal(0L, SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D) & 
  1256.                     (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
  1257.         activate_debugger();
  1258.     }
  1259.  
  1260.     while((msg=(struct IntuiMessage*)GetMsg(W->UserPort))) {
  1261.         class = msg->Class;
  1262.         code  = msg->Code;
  1263.         dmx   = msg->MouseX;
  1264.         dmy   = msg->MouseY;
  1265.         ReplyMsg((struct Message*)msg);
  1266.       
  1267.         switch(class) {
  1268.           case IDCMP_NEWSIZE:
  1269.             inhibit_frame = (W->Flags & WFLG_ZOOMED)?1:0;
  1270.             set_title();
  1271.             break;
  1272.  
  1273.           case IDCMP_REFRESHWINDOW:
  1274.             if(use_low_bandwidth) {
  1275.                 /* hack: this forces refresh */
  1276.                 char *ptr = oldpixbuf;
  1277.                 int i, len = gfxvidinfo.width;
  1278.                 len *= gfxvidinfo.pixbytes;
  1279.                 for(i=0;i<currprefs.gfx_height;++i) {
  1280.                     ptr[00000] ^= 255;
  1281.                     ptr[len-1] ^= 255;
  1282.                     ptr += gfxvidinfo.rowbytes;
  1283.                 }
  1284.                 BeginRefresh(W);
  1285.                 flush_block(0,currprefs.gfx_height-1);
  1286.                 EndRefresh(W, TRUE);
  1287.             } else {
  1288.                 BeginRefresh(W);
  1289.                 EndRefresh(W, TRUE);
  1290.             } break;
  1291.  
  1292.           case IDCMP_CLOSEWINDOW:
  1293.             activate_debugger();
  1294.             break;
  1295.  
  1296.           case IDCMP_RAWKEY: {
  1297.               int kc       = code&127;
  1298.               int released = code&128?1:0;
  1299.             
  1300.               if(released) {
  1301.                   keystate[kc] = 0;
  1302.                   record_key ((kc << 1) | 1);
  1303.               } else if (!keystate[kc])  {
  1304.                   keystate[kc] = 1;
  1305.                   record_key (kc << 1);
  1306.               }
  1307.           } break;
  1308.           
  1309.           case IDCMP_MOUSEMOVE:
  1310.             lastmx += dmx;
  1311.             lastmy += dmy;
  1312.         break;
  1313.  
  1314.           case IDCMP_MOUSEBUTTONS:
  1315.             if(code==SELECTDOWN) buttonstate[0]=1;
  1316.             if(code==SELECTUP)   buttonstate[0]=0;
  1317.             if(code==MENUDOWN)   buttonstate[2]=1;
  1318.             if(code==MENUUP)     buttonstate[2]=0;
  1319.             break;
  1320.         
  1321.           /* Those 2 could be of some use later. */
  1322.           case IDCMP_DISKINSERTED:
  1323.             /*printf("diskinserted(%d)\n",code);*/
  1324.             break;
  1325.           
  1326.           case IDCMP_DISKREMOVED:
  1327.             /*printf("diskremoved(%d)\n",code);*/
  1328.             break;
  1329.                         
  1330.           case IDCMP_ACTIVEWINDOW:
  1331.             inwindow = 1;
  1332.             newmousecounters = 1;
  1333.             break;
  1334.                         
  1335.           case IDCMP_INACTIVEWINDOW:
  1336.             inwindow = 0;
  1337.             break;
  1338.           
  1339.           default:
  1340.             fprintf(stderr, "Unknown class: %d\n",class);
  1341.             break;
  1342.         }
  1343.     }
  1344.     /* "Affengriff" */
  1345.     if(keystate[AK_CTRL] && keystate[AK_LAMI] && keystate[AK_RAMI]) 
  1346.         m68k_reset();
  1347.  
  1348.     /* PC-like :-) CTRL-ALT-DEL => reboot */
  1349.     if(keystate[AK_CTRL] && (keystate[AK_LALT] || keystate[AK_RALT]) && 
  1350.        keystate[AK_DEL]) 
  1351.         m68k_reset();
  1352.  
  1353.     /* CTRL+LSHIFT+LALT+F10 on amiga => F12 on X11 */
  1354.     /*                  F9           => ScrollLock on X11 (inhibit_frame) */
  1355.     if(keystate[AK_CTRL] && keystate[AK_LSH] && keystate[AK_LALT]) {
  1356. /*        if(keystate[AK_F10]) togglemouse(); */
  1357.         if(keystate[AK_F9]) {
  1358.             inhibit_frame = inhibit_frame != 2 ? inhibit_frame ^ 1 : 
  1359.                             inhibit_frame;
  1360.             set_title();
  1361.             if(inhibit_frame) printf("display disabled\n");
  1362.             else printf("display enabled\n");
  1363.         }
  1364.     }
  1365.  
  1366.     disk_hotkeys();
  1367.     gui_handle_events();
  1368.     appw_events();
  1369. }
  1370.  
  1371. /***************************************************************************/
  1372.  
  1373. int debuggable(void)
  1374. {
  1375.     return 1;
  1376. }
  1377.  
  1378. /***************************************************************************/
  1379.  
  1380. int needmousehack(void)
  1381. {
  1382.     return 0;
  1383. }
  1384.  
  1385. /***************************************************************************/
  1386.  
  1387. void LED(int on)
  1388. {
  1389. }
  1390.  
  1391. /***************************************************************************/
  1392.  
  1393. /* sam: need to put all this in a separate module */
  1394.  
  1395. #ifdef PICASSO96
  1396.  
  1397. void DX_Invalidate (int first, int last)
  1398. {
  1399. }
  1400.  
  1401. int DX_BitsPerCannon (void)
  1402. {
  1403.     return 8;
  1404. }
  1405.  
  1406. void DX_SetPalette(int start, int count)
  1407. {
  1408. }
  1409.  
  1410. int DX_FillResolutions (uae_u16 *ppixel_format)
  1411. {
  1412.     return 0;
  1413. }
  1414.  
  1415. void gfx_set_picasso_modeinfo (int w, int h, int depth)
  1416. {
  1417. }
  1418.  
  1419. void gfx_set_picasso_baseaddr (uaecptr a)
  1420. {
  1421. }
  1422.  
  1423. void gfx_set_picasso_state (int on)
  1424. {
  1425. }
  1426.  
  1427. void begindrawing (void)
  1428. {
  1429. }
  1430.  
  1431. void enddrawing (void)
  1432. {
  1433. }
  1434.  
  1435. uae_u8 *lockscr (void)
  1436. {
  1437. return NULL;
  1438. }
  1439.  
  1440. void unlockscr (void)
  1441. {
  1442. }
  1443. #endif
  1444.  
  1445. /***************************************************************************/
  1446.  
  1447. static int led_state[5];
  1448.  
  1449. static void set_title(void)
  1450. {
  1451.     static char title[80];
  1452.     static char ScreenTitle[100];
  1453.  
  1454.     if(!usepub) return;
  1455.  
  1456.     sprintf(title,"%sPower: [%c] Drives: [%c] [%c] [%c] [%c]",
  1457.             inhibit_frame?"UAE (PAUSED) - ":"UAE ­ ",
  1458.             led_state[0]?'X':' ',
  1459.             led_state[1]?'0':' ',
  1460.             led_state[2]?'1':' ',
  1461.             led_state[3]?'2':' ',
  1462.             led_state[4]?'3':' ');
  1463.     
  1464.     if(!*ScreenTitle) {
  1465.          sprintf(ScreenTitle,
  1466.                  "UAE-%d.%d.%d © by Bernd Schmidt & contributors, "
  1467.                  "Amiga Port by Samuel Devulder.",
  1468.                   (version / 100) % 10, (version / 10) % 10, version % 10);
  1469.         SetWindowTitles(W, title, ScreenTitle);
  1470.     } else SetWindowTitles(W, title, (char*)-1);
  1471. }
  1472.  
  1473. /****************************************************************************/
  1474.  
  1475. void main_window_led(int led, int on)                /* is used in amigui.c */
  1476. {
  1477.   if(led>=0 && led<=4) led_state[led] = on;
  1478.   set_title();
  1479. }
  1480.  
  1481. /****************************************************************************/
  1482.  
  1483. static void unrecord(int kc)
  1484. {
  1485.     keystate[kc] = 0;
  1486.     record_key ((kc << 1) | 1);
  1487. }
  1488.  
  1489. /****************************************************************************/
  1490.  
  1491. static void disk_hotkeys(void)
  1492. {
  1493.     struct FileRequester *FileRequest;
  1494.     char buff[80];
  1495.     int drive;
  1496.     char *last_file,*last_dir,*s;
  1497.  
  1498.     if(!(keystate[AK_CTRL] && keystate[AK_LALT])) return;
  1499.  
  1500.     /* CTRL-LSHIFT-LALT F1-F4 => eject_disk */
  1501.     if(keystate[AK_LSH]) {
  1502.         int ok = 0;
  1503.  
  1504.         if(keystate[AK_F1]) {ok=1;disk_eject(0);
  1505.                              printf("drive DF0: ejected\n");}
  1506.         if(keystate[AK_F2]) {ok=1;disk_eject(1);
  1507.                              printf("drive DF1: ejected\n");}
  1508.         if(keystate[AK_F3]) {ok=1;disk_eject(2);
  1509.                              printf("drive DF2: ejected\n");}
  1510.         if(keystate[AK_F4]) {ok=1;disk_eject(3);
  1511.                              printf("drive DF3: ejected\n");}
  1512.  
  1513.         if(ok) {
  1514.             unrecord(AK_CTRL);unrecord(AK_LALT);unrecord(AK_LSH); 
  1515.             unrecord(AK_F1);unrecord(AK_F2);  
  1516.             unrecord(AK_F3);unrecord(AK_F4);
  1517.         }
  1518.         return;
  1519.     }
  1520.  
  1521.     /* CTRL-LALT F1-F4 => insert_disk */
  1522.     if(keystate[AK_F1])      {drive = 0;unrecord(AK_F1);}
  1523.     else if(keystate[AK_F2]) {drive = 1;unrecord(AK_F2);}
  1524.     else if(keystate[AK_F3]) {drive = 2;unrecord(AK_F3);}
  1525.     else if(keystate[AK_F4]) {drive = 3;unrecord(AK_F4);}
  1526.     else return;
  1527.     unrecord(AK_CTRL);unrecord(AK_LALT); 
  1528.  
  1529.     switch(drive) {
  1530.       case 0: case 1: case 2: case 3: last_file = currprefs.df[drive]; break;
  1531.       default: return;
  1532.     }
  1533.  
  1534.     split_dir_file(from_unix_path(last_file), &last_dir, &last_file);
  1535.     if(!last_file) return;
  1536.     if(!last_dir)  return;
  1537.  
  1538.     if(!AslBase) AslBase = OpenLibrary("asl.library",36);
  1539.     if(!AslBase) {
  1540.         fprintf(stderr,"Can't open asl.library v36 !");
  1541.         return;
  1542.     }
  1543.  
  1544.     FileRequest = AllocAslRequest(ASL_FileRequest,NULL);
  1545.     if(!FileRequest) {
  1546.         fprintf(stderr,"Unable to allocate file requester.\n");
  1547.         return;
  1548.     }
  1549.  
  1550.     sprintf(buff,"Select file to use for drive DF%d:",drive);
  1551.     if(AslRequestTags(FileRequest,
  1552.                       use_graffiti?TAG_IGNORE:
  1553.                       ASLFR_Window,         (ULONG)W,
  1554.                       ASLFR_TitleText,      (ULONG)buff,
  1555.                       ASLFR_InitialDrawer,  (ULONG)last_dir,
  1556.                       ASLFR_InitialFile,    (ULONG)last_file,
  1557.                       ASLFR_InitialPattern, (ULONG)"(#?.ad(f|z)#?|df?|?)",
  1558.                       ASLFR_DoPatterns,     TRUE,
  1559.                       ASLFR_RejectIcons,    TRUE,
  1560.                       TAG_DONE)) {
  1561.         free(last_file);
  1562.         last_file = malloc(3 + strlen(FileRequest->fr_Drawer) +
  1563.                            strlen(FileRequest->fr_File));
  1564.         if((last_file)) {
  1565.             s = last_file;
  1566.             strcpy(s,FileRequest->fr_Drawer);
  1567.             if(*s && !(s[strlen(s)-1]==':' || s[strlen(s)-1]=='/')) 
  1568.                 strcat(s,"/");
  1569.             strcat(s,FileRequest->fr_File);
  1570.             last_file = to_unix_path(s);free(s);
  1571.         }
  1572.     } else {
  1573.         free(last_file);
  1574.         last_file = NULL;
  1575.     }
  1576.     FreeAslRequest(FileRequest);
  1577.     free(last_dir);
  1578.  
  1579.     if(last_file) {
  1580.         disk_insert(drive,last_file);
  1581.         free(last_file);
  1582.     }
  1583. }
  1584.  
  1585. /****************************************************************************/
  1586. /*
  1587.  * Routines for OS2.0 (code taken out of mpeg_play by Michael Balzer)
  1588.  */
  1589. static struct BitMap *myAllocBitMap(ULONG sizex, ULONG sizey, ULONG depth, 
  1590.                                     ULONG flags, struct BitMap *friend_bitmap)
  1591. {
  1592.     struct BitMap *bm;
  1593.     unsigned long extra;
  1594.     
  1595.     if(os39) return AllocBitMap(sizex, sizey, depth, flags, friend_bitmap);
  1596.     
  1597.     extra = (depth > 8) ? depth - 8 : 0;
  1598.     bm = AllocVec( sizeof *bm + (extra * 4), MEMF_CLEAR );
  1599.     
  1600.     if( bm )
  1601.       {
  1602.           ULONG i;
  1603.           InitBitMap(bm, depth, sizex, sizey);
  1604.           for( i=0; i<depth; i++ )
  1605.             {
  1606.                 if( !(bm->Planes[i] = AllocRaster(sizex, sizey)) )
  1607.                   {
  1608.                       while(i--) FreeRaster(bm->Planes[i], sizex, sizey);
  1609.                       FreeVec(bm);
  1610.                       bm = 0;
  1611.                       break;
  1612.                   }
  1613.             }
  1614.       }
  1615.     return bm;
  1616. }
  1617.  
  1618. /****************************************************************************/
  1619.  
  1620. static void myFreeBitMap(struct BitMap *bm)
  1621. {
  1622.     if(os39) {FreeBitMap(bm);return;}
  1623.     while(bm->Depth--)
  1624.       FreeRaster(bm->Planes[bm->Depth], bm->BytesPerRow*8, bm->Rows);
  1625.     FreeVec(bm);
  1626. }
  1627.  
  1628. /****************************************************************************/
  1629. /*
  1630.  * find the best appropriate color. return -1 if none is available
  1631.  */
  1632. static LONG ObtainColor(ULONG r,ULONG g,ULONG b)
  1633. {
  1634.     int i, crgb;
  1635.     int colors;
  1636.  
  1637.     if(use_graffiti) {
  1638.         if(maxpen >= 256) {
  1639.             fprintf(stderr,"Asking more than 256 colors for graffiti ?\n");
  1640.             abort();
  1641.         }
  1642.         graffiti_SetRGB(maxpen, r>>24, g>>24, b>>24);
  1643.         return maxpen++;
  1644.     }
  1645.  
  1646.     if(os39 && usepub && CM) {
  1647.         i = ObtainBestPen(CM,r,g,b,
  1648.                           OBP_Precision, (use_approx_color?PRECISION_GUI:
  1649.                                                            PRECISION_EXACT),
  1650.                           OBP_FailIfBad, TRUE,
  1651.                           TAG_DONE);
  1652.         if(i != -1) {
  1653.             if(maxpen<256) pen[maxpen++] = i;
  1654.             else i = -1;
  1655.         }
  1656.         return i;
  1657.     }
  1658.  
  1659.     if(os39 && use_cyb) {
  1660.         if(maxpen >= 256) return -1;
  1661.         SetRGB32(&S->ViewPort, maxpen, r, g, b);
  1662.         return maxpen++;
  1663.     }
  1664.  
  1665.     r >>= 28; g >>= 28; b >>= 28;
  1666.         
  1667.     colors = is_halfbrite?32:(1<<RPDepth(RP));
  1668.   
  1669.     /* private screen => standard allocation */
  1670.     if(!usepub) {
  1671.         if(maxpen >= colors) return -1; /* no more colors available */
  1672.         SetRGB4(&S->ViewPort, maxpen, r, g, b);
  1673.         return maxpen++;
  1674.     }
  1675.  
  1676.     /* public => find exact match */
  1677.     if(use_approx_color) return get_nearest_color(r,g,b);
  1678.     crgb = (r<<8)|(g<<4)|b;
  1679.     for(i=0; i<colors; i++ ) {
  1680.         int rgb = GetRGB4(CM, i);
  1681.         if(rgb == crgb) return i;
  1682.     }
  1683.     return -1;
  1684. }
  1685.  
  1686. /****************************************************************************/
  1687. /*
  1688.  * free a color entry
  1689.  */
  1690. static void ReleaseColors(void)
  1691. {
  1692.     if(os39 && usepub && CM) 
  1693.         while(maxpen>0) ReleasePen(CM, pen[--maxpen]);
  1694.     else maxpen = 0;
  1695. }
  1696.  
  1697. /****************************************************************************/
  1698.  
  1699. static int DoSizeWindow(struct Window *W,int wi,int he)
  1700. {
  1701.     register int x,y;
  1702.     int ret = 1;
  1703.     
  1704.     wi += W->BorderRight + W->BorderLeft;
  1705.     he += W->BorderBottom + W->BorderTop;
  1706.     x   = W->LeftEdge;
  1707.     y   = W->TopEdge;
  1708.     
  1709.     if(x + wi >= W->WScreen->Width)  x = W->WScreen->Width - wi;
  1710.     if(y + he >= W->WScreen->Height) y = W->WScreen->Height - he;
  1711.  
  1712.     if(x<0 || y<0) {
  1713.         fprintf(stderr, "Working screen too small to open window (%dx%d)!\n",
  1714.                 wi, he);
  1715.         if(x<0) {x = 0; wi = W->WScreen->Width;}
  1716.         if(y<0) {y = 0; he = W->WScreen->Height;}
  1717.         ret = 0;
  1718.     }
  1719.     
  1720.     x  -= W->LeftEdge;
  1721.     y  -= W->TopEdge;
  1722.     wi -= W->Width;
  1723.     he -= W->Height;
  1724.     
  1725.     if(x|y)   MoveWindow(W,x,y);
  1726.     if(wi|he) SizeWindow(W,wi,he);
  1727.     return ret;
  1728. }
  1729.  
  1730. /****************************************************************************/
  1731. /*
  1732.  * support code for graffiti card
  1733.  */
  1734. static void graffiti_SetRGB(int i, int r, int g, int b)
  1735. {
  1736.     UWORD **ptr = (void*)RP->BitMap->Planes;
  1737.  
  1738.     *(*ptr++ + i) = 0x0406;
  1739.     *(*ptr++ + i) = (i<<8)|((g>>2)&0x3f);
  1740.     *(*ptr++ + i) = 0x0606;
  1741.     *(*ptr   + i) = ((r<<6)&0x3f00)|((b>>2)&0x3f);
  1742. }
  1743.  
  1744. /****************************************************************************/
  1745.  
  1746. static void graffiti_WritePixelLine8(int x, int y, short len, char *line)
  1747. {
  1748. #if 0
  1749.     /* standard code */
  1750.     char **ptr = (void*)RP->BitMap->Planes;
  1751.  
  1752.     y += 8;
  1753.     x += (y*80)<<2;
  1754.     while(len--) {
  1755.         *(ptr[x&3] + (x>>2)) = *line++;
  1756.         ++x;
  1757.     }
  1758. #else
  1759.     /* this one must be quite fast for 680x0 processor */
  1760.     char **ptr;
  1761.     char *ptr0,*ptr1,*ptr2,*ptr3;
  1762.     ptr = (void*)RP->BitMap->Planes;
  1763.     switch(x&3) {
  1764.         case 0: ptr0=*ptr++;     ptr1=*ptr++;     ptr2=*ptr++;     ptr3=*ptr; break;
  1765.         case 1: ptr3=*ptr++ + 1; ptr0=*ptr++;     ptr1=*ptr++;     ptr2=*ptr; break;
  1766.         case 2: ptr2=*ptr++ + 1; ptr3=*ptr++ + 1; ptr0=*ptr++;     ptr1=*ptr; break;
  1767.         default:
  1768.         case 3: ptr1=*ptr++ + 1; ptr2=*ptr++ + 1; ptr3=*ptr++ + 1; ptr0=*ptr; break;
  1769.     }
  1770.     x >>= 2; x += (80*(y+8));
  1771.     ptr0 += x; ptr1 += x; ptr2 += x; ptr3 += x;
  1772.     ++len;
  1773.     /* full speed here */
  1774.     while(1) {
  1775.         if(--len) *ptr0++ = *line++; else break;
  1776.         if(--len) *ptr1++ = *line++; else break;
  1777.         if(--len) *ptr2++ = *line++; else break;
  1778.         if(--len) *ptr3++ = *line++; else break;
  1779.     }
  1780. #endif
  1781. }
  1782.  
  1783. /****************************************************************************/
  1784.  
  1785. #define MAKEID(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|d)
  1786.  
  1787. static int SaveIFF(char *filename, struct Screen *scr)
  1788. {
  1789.     struct DisplayInfo DI;
  1790.     FILE *file;
  1791.     ULONG BODYsize;
  1792.     ULONG modeid;
  1793.     ULONG count;
  1794.     ULONG i;
  1795.     
  1796.     struct {ULONG iff_type, iff_length;} chunk;
  1797.     struct {ULONG fc_type, fc_length, fc_subtype;} FORM;
  1798.     struct {
  1799.         UWORD w,h,x,y;
  1800.         UBYTE depth,masking,compression,pad1;
  1801.         UWORD transparentColor;
  1802.         UBYTE xAspect,yAspect;
  1803.         WORD  pagewidth,pageheight;
  1804.     } BMHD;
  1805.     
  1806.     BODYsize = scr->BitMap.Depth * scr->BitMap.Rows * 2 * ((scr->Width+15)/16);
  1807.     modeid   = GetVPModeID(&S->ViewPort);
  1808.     count    = scr->ViewPort.ColorMap->Count;
  1809.     
  1810.     FORM.fc_type    = MAKEID('F','O','R','M');
  1811.     FORM.fc_length  = 4 +                 /* ILBM */
  1812.                       8 + sizeof(BMHD) +  /* BMHD */
  1813.                       8 + 4 +             /* CAMG */
  1814.                       8 + 3*count +       /* CMAP */
  1815.                       8 + BODYsize;       /* BODY */
  1816.     FORM.fc_subtype = MAKEID('I','L','B','M');
  1817.     
  1818.     if(!(file = fopen(filename,"w"))) return 0;
  1819.     if(fwrite(&FORM,sizeof(FORM),1,file)!=1) goto err;
  1820.  
  1821.     BMHD.w           = 
  1822.     BMHD.pagewidth   = scr->Width;
  1823.     BMHD.h           = 
  1824.     BMHD.pageheight  = scr->Height;
  1825.     BMHD.x           = 0;
  1826.     BMHD.y           = 0;
  1827.     BMHD.depth       = scr->BitMap.Depth;
  1828.     BMHD.masking     = 0;
  1829.     BMHD.compression = 0;
  1830.     BMHD.pad1        = 0;
  1831.     BMHD.transparentColor = 0;
  1832.     BMHD.xAspect     = 22;
  1833.     BMHD.yAspect     = 11;
  1834.  
  1835.     if(GetDisplayInfoData(NULL, (UBYTE *)&DI, sizeof(struct DisplayInfo), 
  1836.                           DTAG_DISP, modeid)) {
  1837.     BMHD.xAspect     = DI.Resolution.x;
  1838.     BMHD.yAspect     = DI.Resolution.y;
  1839.     }
  1840.  
  1841.     chunk.iff_type   = MAKEID('B','M','H','D');
  1842.     chunk.iff_length = sizeof(BMHD);
  1843.     if(fwrite(&chunk,sizeof(chunk),1,file)!=1 
  1844.     || fwrite(&BMHD, sizeof(BMHD), 1,file)!=1) goto err;
  1845.  
  1846.     chunk.iff_type   = MAKEID('C','A','M','G');
  1847.     chunk.iff_length = sizeof(modeid);
  1848.     if(fwrite(&chunk, sizeof(chunk),   1,file)!=1
  1849.     || fwrite(&modeid,chunk.iff_length,1,file)!=1) goto err;
  1850.  
  1851.    chunk.iff_type    = MAKEID('C','M','A','P');
  1852.    chunk.iff_length  = 3 * count;
  1853.    if(fwrite(&chunk,sizeof(chunk),1,file)!=1) goto err;
  1854.    for(i=0; i<count; ++i) {
  1855.       ULONG c = GetRGB4(scr->ViewPort.ColorMap, i);
  1856.       UBYTE d;
  1857.       d = (c>>8)&15;d |= d<<4;if(fwrite(&d,1,1,file)!=1) goto err;
  1858.       d = (c>>4)&15;d |= d<<4;if(fwrite(&d,1,1,file)!=1) goto err;
  1859.       d = (c>>0)&15;d |= d<<4;if(fwrite(&d,1,1,file)!=1) goto err;
  1860.    }
  1861.  
  1862.    chunk.iff_type    = MAKEID('B','O','D','Y');
  1863.    chunk.iff_length  = BODYsize;
  1864.    if(fwrite(&chunk,sizeof(chunk),1,file)!=1) goto err;
  1865.    {
  1866.    int r,p;
  1867.    struct BitMap *bm = S->RastPort.BitMap;
  1868.    for(r=0; r<bm->Rows; ++r) for(p=0; p<bm->Depth; ++p)
  1869.    if(fwrite(bm->Planes[p] + r*bm->BytesPerRow, 2*((S->Width+15)/16), 1, file)!=1) goto err;
  1870.    }
  1871.    
  1872.    fclose(file);
  1873.    return 1;
  1874. err: 
  1875.    fprintf(stderr,"Error writing to \"%s\"\n",filename);
  1876.    fclose(file);
  1877.    return 0;
  1878.    }
  1879.  
  1880. void write_log (const char *buf)
  1881. {
  1882.     fprintf (stderr, buf);
  1883. }
  1884.  
  1885. /****************************************************************************/
  1886. /* Here lies an algorithm to convert a 12bits truecolor buffer into a HAM
  1887.  * buffer. That algorithm is quite fast and if you study it closely, you'll
  1888.  * understand why there is no need for MMX cpu to subtract three numbers in
  1889.  * the same time. I can think of a quicker algorithm but it'll need 4096*4096
  1890.  * = 1<<24 = 16Mb of memory. That's why I'm quite proud of this one which
  1891.  * only need roughly 64Kb (could be reduced down to 40Kb, but it's not
  1892.  * worth as I use cidx as a buffer which is 128Kb long)..
  1893.  ****************************************************************************/
  1894.  
  1895. static int dist4(LONG rgb1, LONG rgb2) /* computes distance very quickly */
  1896. {
  1897.     int d = 0, t;
  1898.     t = (rgb1&0xF00)-(rgb2&0xF00); t>>=8; if (t<0) d -= t; else d += t;
  1899.     t = (rgb1&0x0F0)-(rgb2&0x0F0); t>>=4; if (t<0) d -= t; else d += t;
  1900.     t = (rgb1&0x00F)-(rgb2&0x00F); t>>=0; if (t<0) d -= t; else d += t;
  1901. #if 0
  1902.     t = rgb1^rgb2; 
  1903.     if(t&15) ++d; t>>=4;
  1904.     if(t&15) ++d; t>>=4;
  1905.     if(t&15) ++d;
  1906. #endif
  1907.     return d;
  1908. }
  1909.  
  1910. #define d_dst (00000+(UBYTE*)cidx) /* let's use cidx as a buffer */
  1911. #define d_cmd (16384+(UBYTE*)cidx)
  1912. #define h_buf (32768+(UBYTE*)cidx)
  1913.  
  1914. static int init_ham(void)
  1915. {
  1916.     int i,t,RGB;
  1917.  
  1918.     /* try direct color first */
  1919.     for(RGB=0;RGB<4096;++RGB) {
  1920.         int c,d;
  1921.         c = d = 50;
  1922.         for(i=0;i<16;++i) {
  1923.             t = dist4(i*0x111, RGB);
  1924.             if(t<d) {
  1925.                 d = t;
  1926.                 c = i;
  1927.             }
  1928.         }
  1929.         i = (RGB&0x00F) | ((RGB&0x0F0)<<1) | ((RGB&0xF00)<<2);
  1930.         d_dst[i] = (d<<2)|3; /* the "|3" is a trick to speedup comparison */
  1931.         d_cmd[i] = c;        /* in the conversion process */
  1932.     }
  1933.     /* then hold & modify */
  1934.     for(i=0;i<32768;++i) {
  1935.         int dr, dg, db, d, c;
  1936.         dr = (i>>10) & 0x1F; dr -= 0x10;if(dr<0) dr = -dr;
  1937.         dg = (i>>5)  & 0x1F; dg -= 0x10;if(dg<0) dg = -dg;
  1938.         db = (i>>0)  & 0x1F; db -= 0x10;if(db<0) db = -db;
  1939.         c  = 0; d = 50;
  1940.         t = dist4(0,  0*256 + dg*16 + db); if(t < d) {d = t;c = 0;}
  1941.         t = dist4(0, dr*256 +  0*16 + db); if(t < d) {d = t;c = 1;}
  1942.         t = dist4(0, dr*256 + dg*16 +  0); if(t < d) {d = t;c = 2;}
  1943.         h_buf[i] = (d<<2) | c;
  1944.     }
  1945.     return 1;
  1946. }
  1947.  
  1948. /* great algorithm: convert trucolor into ham using precalc buffers */
  1949. static void ham_conv(UWORD *src, UBYTE *buf, UWORD len)
  1950. {
  1951.     /* A good compiler (ie. gcc :) will use bfext/bfins instructions */
  1952. #ifdef __SASC
  1953.     union { struct { unsigned int _:17, r:5, g:5, b:5; } _; 
  1954.         int all;} rgb, RGB;
  1955. #else
  1956.     union { struct { UWORD _:1,r:5,g:5,b:5;} _; UWORD all;} rgb, RGB;
  1957. #endif
  1958.     rgb.all = 0;
  1959.     while(len--) {
  1960.         UBYTE c,t;
  1961.         RGB.all = *src++;
  1962.         c = d_cmd[RGB.all];
  1963.         /* cowabonga! */
  1964.         t = h_buf[16912 + RGB.all - rgb.all];
  1965.         if(t<=d_dst[RGB.all]) {
  1966.             if(!(t&=3))   {c = 32; c |= (rgb._.r = RGB._.r);}
  1967.             else if(!--t) {c = 48; c |= (rgb._.g = RGB._.g);}
  1968.             else          {c = 16; c |= (rgb._.b = RGB._.b);}
  1969.         } else rgb._.r = rgb._.g = rgb._.b = c;
  1970.         *buf++ = c;
  1971.     }
  1972. }
  1973.  
  1974.